﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Server
{
    public partial class Server : Form
    {
        private Socket _server;
        private Dictionary<string, Socket> _clients = new Dictionary<string, Socket>();
        public Server()
        {
            InitializeComponent();
            //关闭跨线程访问检查
            CheckForIllegalCrossThreadCalls = false;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //实现监听客户端
            //1.创建服务端套接字，使用IPV4，字节流，TCP协议
            _server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //2.绑定本机IP地址和8888端口号
            _server.Bind(new IPEndPoint(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text)));
            textBox3.AppendText("服务端准备完毕，等待客户端的连接...");

            //3.对客户端进行监听
            _server.Listen(10);

            //禁用按钮,防止重复监听客户端
            button1.Enabled = false;

            //5.子线程负责接收新的客户端
            Thread thread1 = new Thread(RecvClient);
            thread1.IsBackground = true;
            thread1.Start();
        }

        private void RecvClient()
        {
            while (true)
            {
                //4.阻塞等待客户端的连接
                Socket client = _server.Accept();
                textBox3.AppendText("\r\n服务端接收到了客户端的连接: " + client.RemoteEndPoint);

                //将客户端存储到客户端集合中去
                _clients.Add(client.RemoteEndPoint.ToString(), client);
                string clientInfo = client.RemoteEndPoint.ToString();

                //将新客户端信息广播给所有已连接的客户端
                BroadcastClientInfo(clientInfo);

                //将客户端信息添加到下拉列表中去
                comboBox1.Items.Add(client.RemoteEndPoint.ToString());

                //向新客户端发送已有客户端的信息
                SendExistingClientsInfo(client);

                //用子线程来接受客户端发来的消息
                Thread thread = new Thread(RecvClientMsg);
                thread.IsBackground = true;
                thread.Start(client);
            }

        }
        private void SendExistingClientsInfo(Socket newClient)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("4");
            foreach (string client in _clients.Keys)
            {
                if (client != newClient.RemoteEndPoint.ToString())
                {
                    sb.Append(client).Append("|");
                }
            }
            byte[] buffer = Encoding.UTF8.GetBytes(sb.ToString());
            newClient.Send(buffer);
        }

        //接收客户端的消息
        private void RecvClientMsg(object obj)
        {
            //当前接收到的客户端
            Socket currentClient = obj as Socket;
            try
            {
                //需要循环接收客户端发来的消息
                while (true)
                {
                    //5.阻塞等待客户端发来的消息
                    byte[] buffer = new byte[1024];
                    int length = currentClient.Receive(buffer);
                    string sourceClient = currentClient.RemoteEndPoint.ToString();
                    SendMsgToTargetClient(sourceClient, buffer, length);
                }

            }
            catch (SocketException ex)
            {
                textBox4.AppendText("\r\n" + currentClient.RemoteEndPoint + ": 客户端掉线了");
                //移除掉线客户端
                string clientKey = currentClient.RemoteEndPoint.ToString();
                _clients.Remove(clientKey);
                comboBox1.Items.Remove(currentClient.RemoteEndPoint.ToString());

                //广播客户端掉线信息
                BroadcastClientDisconnect(clientKey);
            }
        }
        private void BroadcastClientDisconnect(string disconnectedClient)
        {
            byte[] buffer = Encoding.UTF8.GetBytes("[5]" + disconnectedClient); // 自定义消息格式，例如 [4] 表示客户端掉线消息
            foreach (var client in _clients.Values)
            {
                try
                {
                    client.Send(buffer);
                }
                catch (SocketException ex)
                {
                    // 处理发送异常，例如移除发送失败的客户端
                    string failedClient = client.RemoteEndPoint.ToString();
                    _clients.Remove(failedClient);
                }
            }
        }
        private void BroadcastClientInfo(string newClientInfo)
        {
            byte[] messageType = new byte[] { 4 };  // 4 表示新客户端信息消息类型
            byte[] clientInfoBytes = Encoding.UTF8.GetBytes(newClientInfo);
            byte[] buffer = new byte[messageType.Length + clientInfoBytes.Length];
            messageType.CopyTo(buffer, 0);
            clientInfoBytes.CopyTo(buffer, messageType.Length);
            foreach (Socket client in _clients.Values)
            {
                if (client.RemoteEndPoint.ToString() != newClientInfo) // 避免将信息发送给新连接的客户端自身
                {
                    try
                    {
                        client.Send(buffer);
                    }
                    catch (SocketException ex)
                    {
                        // 处理发送异常，例如移除发送失败的客户端
                        Console.WriteLine($"Failed to send client info to {client.RemoteEndPoint}: {ex.Message}");
                    }
                }
            }
        }

        //处理文本信息到目标客户端
        private string GetTargetClientFromMessage(byte[] buffer, int length)
        {
            //这里假设消息中包含目标客户端的信息，从消息中解析出目标客户端
            // 消息格式为：[targetClientLength][targetClient][Message]
            int targetClientLength = buffer[1];
            int startIndex = 2;
            string targetClient = Encoding.UTF8.GetString(buffer, startIndex, targetClientLength);
            return targetClient;
        }
        private void SendMsgToTargetClient(string sourceClient, byte[] buffer, int length)
        {
            //处理文本消息，转发给目标客户端
            string targetClient = GetTargetClientFromMessage(buffer, length);
            if (_clients.ContainsKey(targetClient))
            {
                _clients[targetClient].Send(buffer);
            }
            if (buffer[0] == 1)
            {
                textBox3.AppendText("\r\n" + sourceClient + "发送文本消息给: " + targetClient);
            }
            else if (buffer[0] == 2)
            {
                textBox3.AppendText("\r\n" + sourceClient + "发送文件消息给: " + targetClient);
            }
            else if (buffer[0] == 3)
            {
                textBox3.AppendText("\r\n" + sourceClient + "发送抖动消息给: " + targetClient);
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            //读取输入框中的文本
            byte[] buffer = Encoding.UTF8.GetBytes(textBox4.Text);

            //将读取的文本放入到一个新的buffer中，其中新的buffer的下标0 用于区分文本和文件资源
            //1: 表示存储的是文本， 2: 表示存储的文件
            byte[] newBuf = new byte[buffer.Length + 1];
            newBuf[0] = 1;
            Array.Copy(buffer, 0, newBuf, 1, buffer.Length);

            if (!string.IsNullOrEmpty(comboBox1.Text))
            {
                //向客户端发送数据
                _clients[comboBox1.Text].Send(newBuf);
                textBox4.Clear();
            }
            else
            {
                MessageBox.Show("请选择回复的客户端");
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //1.创建文件对话框
            OpenFileDialog ofd = new OpenFileDialog();

            //设置文本对话框对象
            ofd.Title = "请选择打开的文件";

            //设置是否允许选择多个文件
            ofd.Multiselect = false; //默认为false

            //设置访问的文件夹路径
            ofd.InitialDirectory = "D:\\";

            //设置文件过滤器
            ofd.Filter = "文本文件|*.txt|视频|*.mp4|其它|*.*";

            //2.展示文本对话框
            ofd.ShowDialog();

            //3.获取被选择文件的路径和文件名
            string fileName = ofd.FileName;
            textBox5.Text = fileName;

            if (!string.IsNullOrEmpty(fileName))
            {
                //4.获取被选中文件的输入流
                Stream stream = ofd.OpenFile();

                //读取内容的长度
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);

                //字节数组下标0为2：文件
                byte[] newBuf = new byte[stream.Length + 1];
                newBuf[0] = 2;
                Array.Copy(buffer, 0, newBuf, 1, buffer.Length);

                if (!string.IsNullOrEmpty(comboBox1.Text))
                {
                    //5.向客户端发送数据
                    _clients[comboBox1.Text].Send(newBuf);
                }
                else
                {
                    MessageBox.Show("请选择回复的客户端");
                }
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            //字节数组下标0为3：抖动
            byte[] bytes = { 3 };
            if (!string.IsNullOrEmpty(comboBox1.Text))
            {
                _clients[comboBox1.Text].Send(bytes);
            }
            else
            {
                MessageBox.Show("请选择要回复的客户端");
            }
        }
    }
}
